//
//  PLInteractor.h
//  Plankton
//
//  Created by Marc Schlichte on 23.10.08.
//  Copyright 2008-2009 Framework Labs. All rights reserved.
//

#import <Foundation/Foundation.h>

#import "PLPattern.h"	// for message handler/timeout handler

@class PLPlatform;

@protocol PLInteractorContext;


/// Interactors are helper classes out of which actors can be composed. They send and receive
/// messages on behave of the containing actor and need their actor-id and platform as a context
/// to function. This is what this abstract superclass provides.
///
@interface PLInteractor : NSObject 
{
    id<PLInteractorContext> context;
}

- (id)initWithContext:(id<PLInteractorContext>)context; //!< context is not retained

@end

/// This protocol has to be provided by the interactor host - i.e. the actor
///
@protocol PLInteractorContext <NSObject>

- (PLPlatform *)platformForInteractor:(PLInteractor *)interactor;
- (NSString *)aidForInteractor:(PLInteractor *)interactor;

@end

/// A helper object use by asynchronous handlers of the PLResponder class to reply
/// back in an asynchronous fashion.
///
@interface PLResponse : NSObject
{
@private
    PLPlatform  *platform;
    NSString    *name;
    NSString    *sender, *receiver;
    NSNumber    *iid;
}

- (void)sendWithArgs:(id)args; //!< call this method with a plist message to send back to the requestor.

@end

/// A simple interactor which waits for messages sent by a PLRequestor with the specified
/// request name. When such a request arrives, the registered action method is sent to the
/// target which is implicitly given by the interactor context.
///	A syncrhonous handler just returns the message to sent back to the requestor.
/// An asynchronous handler is given a PLResponse object, which provides a method to send
/// back a result at some point in time.
/// Once an incomming request is handled, the responder registers with the platform to receive
/// another message with the same request name.
///
@interface PLResponder : PLInteractor <PLMessageHandler>
{
    SEL         handler;
    PLPattern   *pattern;
    BOOL        isAsync;
}

- (void)serveRequestsNamed:(NSString *)reqName syncHandler:(SEL)reqHandler; //!< (id)onRequest:(id)args
- (void)serveRequestsNamed:(NSString *)reqName asyncHandler:(SEL)reqHandler; //!< (void)onRequest:(id)args response:(PLResponse)resp

- (void)stopServingRequests; //!< call this if you don't wan't to respond to requests with the request-name anymore.

@end

/// A simple interactor which sends message to a waiting responder.
///
@interface PLRequestor : PLInteractor <PLMessageHandler, PLTimeoutHandler>
{
    SEL             responseHandler;
    PLPattern       *responsePattern; // this is not needed for subclasses so factor out
    NSNumber        *iid;
    NSTimeInterval  timeoutInterval;
    SEL             timeoutHandler;
}

- (void)setTimeoutHandler:(SEL)handler after:(NSTimeInterval)interval; //!< (void)onTimeoutOf:(NSString *)aid requestor:(PLRequestor *)req

- (void)sendRequestNamed:(NSString *)name arguments:(id)args to:(NSString *)aid
         responseHandler:(SEL)handler; //!< (void)onResponse:(id)args requestor:(PLRequestor *)req

@end

/// A requestor specialization which allows to send a message to collection of responders at one and
/// wait for their results.
///
@interface PLMulticastRequestor : PLRequestor
{
    SEL             joinHandler;
    NSMutableSet    *outstandingPeers;
}

- (void)multicastRequestNamed:(NSString *)name arguments:(id)args 
                           to:(id<NSFastEnumeration>)aids 
              responseHandler:(SEL)responseHndler
                  joinHandler:(SEL)joinHandler; //!< (void)onJoinOfRequestor:(PLRequestor *)req

@end
